#include "bsp_spi.h" // Device header
#include "../w25q64/bsp_w25q64.h"

/**
 * 函    数：SPI初始化
 * 参    数：无
 * 返 回 值：无
 */
void SPI_Init(ECSPI_Type *base) {
  /* 配置CONREG寄存器
   * bit0 : 		1 	使能ECSPI
   * bit3 : 		1	当向TXFIFO写入数据以后立即开启SPI突发。
   * bit[7:4] : 	0001 SPI通道0主模式，根据实际情况选择，
   *            	   	开发板上的ICM-20608接在SS0上，所以设置通道0为主模式
   * bit[19:18]:	00
   * 选中通道0(其实不需要，因为片选信号我们我们自己控制) bit[31:20]:	0x7
   * 突发长度为8个bit。
   */
  base->CONREG = 0; /* 先清除控制寄存器 */
  base->CONREG |= (0x1 << 0);
  base->CONREG |= (1 << 3) | (1 << 4) | (7 << 20); /* 配置CONREG寄存器 */

  /*
   * ECSPI通道0设置,即设置CONFIGREG寄存器
   * bit0:	0 通道0 PHA为0
   * bit4:	0 通道0 SCLK高电平有效
   * bit8: 	0 通道0片选信号 当SMC为1的时候此位无效
   * bit12：	0 通道0 POL为0  
   * bit16：	0 通道0 数据线空闲时高电平
   * bit20:	0 通道0 时钟线空闲时低电平
   */
  base->CONFIGREG = 0; /* 设置通道寄存器 */

  /*
   * ECSPI通道0设置，设置采样周期
   * bit[14:0] :	0X2000  采样等待周期，比如当SPI时钟为10MHz的时候
   *  		    0X2000就等于1/10000 * 0X2000 = 0.8192ms，也就是连续
   *          	读取数据的时候每次之间间隔0.8ms
   * bit15	 :  0  采样时钟源为SPI CLK
   * bit[21:16]:  0  片选延时，可设置为0~63
   */
  base->PERIODREG = 0X2000; /* 设置采样周期寄存器 */

  /*
   * ECSPI的SPI时钟配置，SPI的时钟源来源于pll3_sw_clk/8=480/8=60MHz
   * 通过设置CONREG寄存器的PER_DIVIDER(bit[11:8])和POST_DIVEDER(bit[15:12])来
   * 对SPI时钟源分频，获取到我们想要的SPI时钟：
   * SPI CLK = (SourceCLK / PER_DIVIDER) / (2^POST_DIVEDER)
   * 比如我们现在要设置SPI时钟为6MHz，那么PER_DIVEIDER和POST_DEIVIDER设置如下：
   * PER_DIVIDER = 0X9。
   * POST_DIVIDER = 0X0。
   * SPI CLK = 60000000/(0X9 + 1) = 60000000=6MHz
   */
  base->CONREG &=
      ~((0XF << 12) | (0XF << 8)); /* 清除PER_DIVDER和POST_DIVEDER以前的设置 */
  base->CONREG |= (0X9 << 12); /* 设置SPI CLK = 6MHz */
}

/**
 * @brief SPI交换传输一个字节，使用SPI模式0
 *
 * @param SPI ECSPI_Type
 * @param ByteSend ByteSend 要发送的一个字节
 * @return uint8_t 接收的一个字节
 */
uint8_t SPI_Mode0_SwapByte(ECSPI_Type *base, unsigned char txdata) {

  uint32_t spirxdata = 0;
  uint32_t spitxdata = txdata;

  /* 选择通道0 */
  base->CONREG &= ~(3 << 18);
  base->CONREG |= (0 << 18);

  while ((base->STATREG & (1 << 0)) == 0) {
  } /* 等待发送FIFO为空 */
  base->TXDATA = spitxdata;

  while ((base->STATREG & (1 << 3)) == 0) {
  } /* 等待接收FIFO有数据 */
  spirxdata = base->RXDATA;
  return spirxdata;
}
